import 'dart:math';

import 'package:flutter/material.dart';

///圆形进度条带刻度
class CircleIndicateWithScale extends StatelessWidget {
  const CircleIndicateWithScale(
      {Key? key,
      required this.width,
      this.gap = 15,
      this.longerScaleLen = 20,
      this.shortScaleLen = 15,
      this.progress = 0,
      this.indicateWidth = 10})
      : super(key: key);

  ///约束刻度的正方形边长
  final double width;

  ///进度条与 刻度之间的间隙 包括进度条宽度
  final double gap;

  ///较长刻度的长度
  final double longerScaleLen;

  ///较短刻度的长度
  final double shortScaleLen;

  /// 进度 0~100
  final int progress;

  /// 进度条宽度
  final double indicateWidth;
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Stack(
        alignment: Alignment.center,
        children: [
          Container(
            width: width,
            height: width,
            child: CustomPaint(
              painter: MyKeDuPaint(width / 2),
            ),
          ),
          Container(
            width: width - longerScaleLen * 2 - gap * 2, // 320 - 20*2 - 15 * 2
            height: width - longerScaleLen * 2 - gap * 2,
            child: CustomPaint(
              painter: MyCircleIndicatePaint(
                  width - longerScaleLen * 2 - gap * 2,
                  width - longerScaleLen * 2 - gap * 2,
                  progress: progress,
                  indicateWidth: indicateWidth),
            ),
          ),
          Container(
            width: 220,
            height: 220,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(110),
              color: Colors.blue.withAlpha(10),
            ),
          ),
          Container(
            width: 200,
            height: 200,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(100),
              color: Colors.blue.withAlpha(100),
            ),
            alignment: Alignment.center,
            child: Container(
              width: 180,
              height: 180,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(90),
                color: Colors.blueAccent,
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    "$progress",
                    style: TextStyle(fontSize: 50, color: Colors.white),
                  ),
                  Text(
                    "%",
                    style: TextStyle(fontSize: 25, color: Colors.white),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

///刻度
class MyKeDuPaint extends CustomPainter {
  /// 半径
  final double radius;

  /// 较长刻度长度
  final double longerScaleLen;

  /// 较短刻度长度
  final double shorterScaleLen;

  /// 刻度宽度
  final double scaleWidth;

  final Color scaleColor;

  // 弧度30
  final radians30 = pi / 6;

  // 弧度24
  final radians24 = pi * 2 / 15;

  // 弧度18
  final radians18 = pi / 10;

  // 弧度12
  final radians12 = pi / 15;

  // 弧度6
  final radians6 = pi / 30;

  // 弧度0
  final radians0 = pi * 0;

  // 弧度36
  final radians36 = pi / 5;

  // 弧度42
  final radians42 = pi * 7 / 30;

  // 弧度48
  final radians48 = pi * 4 / 15;

  // 弧度54
  final radians54 = pi * 3 / 10;

  // 弧度60
  final radians60 = pi / 3;

  // 弧度66
  final radians66 = pi * 11 / 30;

  // 弧度72
  final radians72 = pi * 2 / 5;

  // 弧度78
  final radians78 = pi * 13 / 30;

  // 弧度84
  final radians84 = pi * 7 / 15;

  // 弧度90
  final radians90 = pi / 2;

  MyKeDuPaint(this.radius,
      {this.longerScaleLen = 20,
      this.shorterScaleLen = 15,
      this.scaleWidth = 3,
      this.scaleColor = Colors.blue});

  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint();

    paint.strokeWidth = this.scaleWidth;

    paint.style = PaintingStyle.stroke;

    paint.color = this.scaleColor;

    // 圆心到刻度底部端点的距离 直角三角形的斜边
    final c = this.radius - this.longerScaleLen;

    // 圆心距 较短刻度 顶部端点的距离
    final shorterTop = c + shorterScaleLen;

    //画刻度 从左下角开始
    // 30/180 1/6
    var p1 = Offset(radius - cos(radians30) * c, radius + sin(radians30) * c);
    var p2 = Offset(
        radius - cos(radians30) * radius, radius + sin(radians30) * radius);
    canvas.drawLine(p1, p2, paint);

    // 24/180  2/15
    var p3 = Offset(radius - cos(radians24) * c, radius + sin(radians24) * c);

    var p4 = Offset(radius - cos(radians24) * shorterTop,
        radius + sin(radians24) * shorterTop);

    // 18/180  1/10
    var p5 = Offset(radius - cos(radians18) * c, radius + sin(radians18) * c);
    var p6 = Offset(radius - cos(radians18) * shorterTop,
        radius + sin(radians18) * shorterTop);

    // 12/180  1/15
    var p7 = Offset(radius - cos(radians12) * c, radius + sin(radians12) * c);
    var p8 = Offset(radius - cos(radians12) * shorterTop,
        radius + sin(radians12) * shorterTop);

    // 6/180
    var p9 = Offset(radius - cos(radians6) * c, radius + sin(radians6) * c);
    var p10 = Offset(radius - cos(radians6) * shorterTop,
        radius + sin(radians6) * shorterTop);

    canvas.drawLine(p3, p4, paint);
    canvas.drawLine(p5, p6, paint);
    canvas.drawLine(p7, p8, paint);
    canvas.drawLine(p9, p10, paint);

    // 0/180 0
    var p11 = Offset(radius - cos(radians0) * c, radius + sin(radians0) * c);
    var p12 = Offset(
        radius - cos(radians0) * radius, radius + sin(radians0) * radius);
    canvas.drawLine(p11, p12, paint);

    // 6/180
    var p13 = Offset(radius - cos(radians6) * c, radius - sin(radians6) * c);
    var p14 = Offset(radius - cos(radians6) * shorterTop,
        radius - sin(radians6) * shorterTop);

    // 12/180
    var p15 = Offset(radius - cos(radians12) * c, radius - sin(radians12) * c);
    var p16 = Offset(radius - cos(radians12) * shorterTop,
        radius - sin(radians12) * shorterTop);

    // 18/180
    var p17 = Offset(radius - cos(radians18) * c, radius - sin(radians18) * c);
    var p18 = Offset(radius - cos(radians18) * shorterTop,
        radius - sin(radians18) * shorterTop);

    // 24/180  2/15
    var p19 = Offset(radius - cos(radians24) * c, radius - sin(radians24) * c);
    var p20 = Offset(radius - cos(radians24) * shorterTop,
        radius - sin(radians24) * shorterTop);

    canvas.drawLine(p13, p14, paint);
    canvas.drawLine(p15, p16, paint);
    canvas.drawLine(p17, p18, paint);
    canvas.drawLine(p19, p20, paint);

    // 30/180  1/6
    var p21 = Offset(radius - cos(radians30) * c, radius - sin(radians30) * c);
    var p22 = Offset(
        radius - cos(radians30) * radius, radius - sin(radians30) * radius);
    canvas.drawLine(p21, p22, paint);

    // 36/180  1/5

    var p23 = Offset(radius - cos(radians36) * c, radius - sin(radians36) * c);
    var p24 = Offset(radius - cos(radians36) * shorterTop,
        radius - sin(radians36) * shorterTop);

    // 42/180  7 / 30

    var p25 = Offset(radius - cos(radians42) * c, radius - sin(radians42) * c);
    var p26 = Offset(radius - cos(radians42) * shorterTop,
        radius - sin(radians42) * shorterTop);

    // 48/180  4/15
    var p27 = Offset(radius - cos(radians48) * c, radius - sin(radians48) * c);
    var p28 = Offset(radius - cos(radians48) * shorterTop,
        radius - sin(radians48) * shorterTop);

    // 54/180  3/10

    var p29 = Offset(radius - cos(radians54) * c, radius - sin(radians54) * c);
    var p30 = Offset(radius - cos(radians54) * shorterTop,
        radius - sin(radians54) * shorterTop);

    canvas.drawLine(p23, p24, paint);
    canvas.drawLine(p25, p26, paint);
    canvas.drawLine(p27, p28, paint);
    canvas.drawLine(p29, p30, paint);

    // 60/180  1/3
    var p31 = Offset(radius - cos(radians60) * c, radius - sin(radians60) * c);
    var p32 = Offset(
        radius - cos(radians60) * radius, radius - sin(radians60) * radius);
    canvas.drawLine(p31, p32, paint);

    // 66/180  11 / 30
    var p33 = Offset(radius - cos(radians66) * c, radius - sin(radians66) * c);
    var p34 = Offset(radius - cos(radians66) * shorterTop,
        radius - sin(radians66) * shorterTop);

    // 72/180  2/5

    var p35 = Offset(radius - cos(radians72) * c, radius - sin(radians72) * c);
    var p36 = Offset(radius - cos(radians72) * shorterTop,
        radius - sin(radians72) * shorterTop);

    // 78/180  13/30
    var p37 = Offset(radius - cos(radians78) * c, radius - sin(radians78) * c);
    var p38 = Offset(radius - cos(radians78) * shorterTop,
        radius - sin(radians78) * shorterTop);

    // 84/180  7/15
    var p39 = Offset(radius - cos(radians84) * c, radius - sin(radians84) * c);
    var p40 = Offset(radius - cos(radians84) * shorterTop,
        radius - sin(radians84) * shorterTop);

    canvas.drawLine(p33, p34, paint);
    canvas.drawLine(p35, p36, paint);
    canvas.drawLine(p37, p38, paint);
    canvas.drawLine(p39, p40, paint);

    // 90/180 1/2
    var p41 = Offset(radius - cos(radians90) * c, radius - sin(radians90) * c);
    var p42 = Offset(
        radius - cos(radians90) * radius, radius - sin(radians90) * radius);
    canvas.drawLine(p41, p42, paint);

    // 6/180  1/30
    var p43 = Offset(radius + sin(radians6) * c, radius - cos(radians6) * c);
    var p44 = Offset(radius + sin(radians6) * shorterTop,
        radius - cos(radians6) * shorterTop);

    // 12/180  1/15
    var p45 = Offset(radius + sin(radians12) * c, radius - cos(radians12) * c);
    var p46 = Offset(radius + sin(radians12) * shorterTop,
        radius - cos(radians12) * shorterTop);

    // 18/180  1/10
    var p47 = Offset(radius + sin(radians18) * c, radius - cos(radians18) * c);
    var p48 = Offset(radius + sin(radians18) * shorterTop,
        radius - cos(radians18) * shorterTop);

    // 24/180  2/15
    var p49 = Offset(radius + sin(radians24) * c, radius - cos(radians24) * c);
    var p50 = Offset(radius + sin(radians24) * shorterTop,
        radius - cos(radians24) * shorterTop);
    canvas.drawLine(p43, p44, paint);
    canvas.drawLine(p45, p46, paint);
    canvas.drawLine(p47, p48, paint);
    canvas.drawLine(p49, p50, paint);

    // 30/180 1/6
    var p51 = Offset(radius + sin(radians30) * c, radius - cos(radians30) * c);
    var p52 = Offset(
        radius + sin(radians30) * radius, radius - cos(radians30) * radius);
    canvas.drawLine(p51, p52, paint);

    // 36/180  1/5
    var p53 = Offset(radius + sin(radians36) * c, radius - cos(radians36) * c);
    var p54 = Offset(radius + sin(radians36) * shorterTop,
        radius - cos(radians36) * shorterTop);

    // 42/180  7/30
    var p55 = Offset(radius + sin(radians42) * c, radius - cos(radians42) * c);
    var p56 = Offset(radius + sin(radians42) * shorterTop,
        radius - cos(radians42) * shorterTop);

    // 48/180  4/15
    var p57 = Offset(radius + sin(radians48) * c, radius - cos(radians48) * c);
    var p58 = Offset(radius + sin(radians48) * shorterTop,
        radius - cos(radians48) * shorterTop);

    // 54/180  3/10
    var p59 = Offset(radius + sin(radians54) * c, radius - cos(radians54) * c);
    var p60 = Offset(radius + sin(radians54) * shorterTop,
        radius - cos(radians54) * shorterTop);

    canvas.drawLine(p53, p54, paint);
    canvas.drawLine(p55, p56, paint);
    canvas.drawLine(p57, p58, paint);
    canvas.drawLine(p59, p60, paint);

    // 60/180 1/3
    var p61 = Offset(radius + sin(radians60) * c, radius - cos(radians60) * c);
    var p62 = Offset(
        radius + sin(radians60) * radius, radius - cos(radians60) * radius);
    canvas.drawLine(p61, p62, paint);

    // 66/180  11/30
    var p63 = Offset(radius + sin(radians66) * c, radius - cos(radians66) * c);
    var p64 = Offset(radius + sin(radians66) * shorterTop,
        radius - cos(radians66) * shorterTop);

    // 72/180  2/5
    var p65 = Offset(radius + sin(radians72) * c, radius - cos(radians72) * c);
    var p66 = Offset(radius + sin(radians72) * shorterTop,
        radius - cos(radians72) * shorterTop);

    // 78/180  13/30
    var p67 = Offset(radius + sin(radians78) * c, radius - cos(radians78) * c);
    var p68 = Offset(radius + sin(radians78) * shorterTop,
        radius - cos(radians78) * shorterTop);

    // 84/180  7/15
    var p69 = Offset(radius + sin(radians84) * c, radius - cos(radians84) * c);
    var p70 = Offset(radius + sin(radians84) * shorterTop,
        radius - cos(radians84) * shorterTop);

    canvas.drawLine(p63, p64, paint);
    canvas.drawLine(p65, p66, paint);
    canvas.drawLine(p67, p68, paint);
    canvas.drawLine(p69, p70, paint);

    // 90/180 1/2
    var p71 = Offset(radius + sin(radians90) * c, radius - cos(radians90) * c);
    var p72 = Offset(
        radius + sin(radians90) * radius, radius - cos(radians90) * radius);
    canvas.drawLine(p71, p72, paint);

    // 6/180  1/30
    var p73 = Offset(radius + cos(radians6) * c, radius + sin(radians6) * c);
    var p74 = Offset(radius + cos(radians6) * shorterTop,
        radius + sin(radians6) * shorterTop);

    // 12/180  1/15
    var p75 = Offset(radius + cos(radians12) * c, radius + sin(radians12) * c);
    var p76 = Offset(radius + cos(radians12) * shorterTop,
        radius + sin(radians12) * shorterTop);

    // 18/180  1/10
    var p77 = Offset(radius + cos(radians18) * c, radius + sin(radians18) * c);
    var p78 = Offset(radius + cos(radians18) * shorterTop,
        radius + sin(radians18) * shorterTop);

    // 24/180  2/15
    var p79 = Offset(radius + cos(radians24) * c, radius + sin(radians24) * c);
    var p80 = Offset(radius + cos(radians24) * shorterTop,
        radius + sin(radians24) * shorterTop);

    canvas.drawLine(p73, p74, paint);
    canvas.drawLine(p75, p76, paint);
    canvas.drawLine(p77, p78, paint);
    canvas.drawLine(p79, p80, paint);

    // 30/180 1/6
    var p81 = Offset(radius + cos(radians30) * c, radius + sin(radians30) * c);
    var p82 = Offset(
        radius + cos(radians30) * radius, radius + sin(radians30) * radius);
    canvas.drawLine(p81, p82, paint);
  }

  @override
  bool shouldRepaint(MyKeDuPaint oldDelegate) {
    return oldDelegate.radius != radius ||
        oldDelegate.longerScaleLen != longerScaleLen ||
        oldDelegate.shorterScaleLen != shorterScaleLen;
  }
}

///圆形进度条
class MyCircleIndicatePaint extends CustomPainter {
  ///进度条颜色
  final Color indicateColor;

  ///进度条宽度
  final double indicateWidth;

  ///进度条背景颜色
  final Color? indicateBackgroundColor;

  ///进度 0~100
  final int progress;

  ///矩形宽度
  final double width;

  ///矩形高度
  final double height;

  MyCircleIndicatePaint(this.width, this.height,
      {this.indicateColor = Colors.blue,
      this.indicateWidth = 10,
      this.indicateBackgroundColor,
      this.progress = 10})
      : assert(progress >= 0 || progress <= 100);

  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = indicateWidth;

    //画圆弧背景
    paint.color = indicateBackgroundColor ?? Colors.blue.shade50;
    canvas.drawArc(
        Rect.fromLTWH(0, 0, width, height),
        150 * pi / 180,
        240 * pi / 180,
        false,
        paint);
    paint.color = indicateColor;

    //画圆形进度条
    paint.strokeCap = StrokeCap.round;
    canvas.drawArc(Rect.fromLTWH(0, 0, width, height), 150 * pi / 180,
        progress / 100 * 240 * pi / 180, false, paint);
  }

  @override
  bool shouldRepaint(MyCircleIndicatePaint oldDelegate) {
    return oldDelegate.progress != progress ||
        oldDelegate.indicateColor != indicateColor;
  }
}
